home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xpaint-2.1.1
/
hash.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-03
|
6KB
|
274 lines
/* +-------------------------------------------------------------------+ */
/* | Copyright 1992, David Koblas. | */
/* | Permission to use, copy, modify, and distribute this software | */
/* | and its documentation for any purpose and without fee is hereby | */
/* | granted, provided that the above copyright notice appear in all | */
/* | copies and that both that copyright notice and this permission | */
/* | notice appear in supporting documentation. This software is | */
/* | provided "as is" without express or implied warranty. | */
/* +-------------------------------------------------------------------+ */
/*
** A Simple useful set of hash routines:
**
** void *HashCreate(int (*cmp)(void *, void*), void (*free)(void *), int nelem)
** -- Create a hash table with cmp() function, and optional free() function.
** void HashDestroy(HashTable *tbl)
** -- Destroy the whole hash table
** void *HashFind(HashTable *tbl, int value, void *val)
** -- Find an element in the hash table, returns NULL if not found
** int HashAdd(HashTable *tbl, int value, void *val)
** -- Add an element to the table, returns non-zero on failure
** int HashRemove(HashTable *tbl, int value, void *elem)
** -- Remove a particular hash entry from the table, pointer compairson
** int HashAll(HashTable *tbl, int (*func)(void *))
** -- Apply function to all elements of the table, until func() returns non-zero
*/
#include <stdio.h>
#if 0
#include <malloc.h>
#else
extern void free(void *);
extern void *malloc(unsigned int);
#endif
typedef struct hash_s {
int *val;
struct hash_s *left, *right, *same, **parentp;
} HashElement;
typedef struct {
int (*cmp)(void *, void *);
void (*free)(void *);
HashElement **table;
int nelem;
} HashTable;
/*
** Create a hashtable, with cmp() compare function, and free() free function
** with a hash table width of nelem, free can be null in which case the
** system free function will be used.
*/
void *HashCreate(int (*cmp)(void *, void *), void (*free)(void *), int nelem)
{
HashTable *new;
int i;
new = (HashTable*)malloc(sizeof(HashTable));
new->nelem = nelem;
new->cmp = cmp;
new->free = free;
new->table = (HashElement **)malloc(nelem * sizeof(HashElement*));
for (i = 0; i < nelem; i++)
new->table[i] = NULL;
return (void*)new;
}
static void hashDestory(void (*func)(void *), HashElement *entry)
{
if (entry->left != NULL) {
hashDestory(func, entry->left);
free(entry->left);
}
if (entry->right != NULL) {
hashDestory(func, entry->right);
free(entry->right);
}
if (entry->same != NULL) {
hashDestory(func, entry->same);
free(entry->same);
}
if (entry->val)
func(entry->val);
}
/*
** Free the entire hash table, and all elements
*/
void HashDestroy(HashTable *tbl)
{
int i;
if (tbl == NULL)
return;
for (i = 0; i < tbl->nelem; i++) {
if (tbl->table[i] != NULL) {
hashDestory(tbl->free ? tbl->free : free, tbl->table[i]);
free(tbl->table[i]);
}
}
free(tbl->table);
free(tbl);
}
/*
** Find a particular element in the hash table, returns NULL if it isn't found
*/
void *HashFind(HashTable *tbl, int value, void *val)
{
HashElement *cur;
int v;
if (tbl == NULL)
return NULL;
cur = tbl->table[value];
while (cur != NULL) {
if ((v = tbl->cmp(cur->val, val)) == 0)
return cur->val;
if (v < 0)
cur = cur->left;
else
cur = cur->right;
}
return NULL;
}
/*
** And a new element to the has table, returns non-zero on failure
*/
int HashAdd(HashTable *tbl, int value, void *val)
{
HashElement *new = (HashElement*)malloc(sizeof(HashElement));
HashElement *cur = tbl->table[value];
HashElement **prev;
int v;
if (new == NULL || tbl == NULL)
return 1;
new->left = NULL;
new->right = NULL;
new->same = NULL;
new->val = val;
new->parentp = NULL;
prev = &tbl->table[value];
while (cur != NULL) {
if ((v = tbl->cmp(cur->val, val)) < 0) {
prev = &cur->left;
cur = cur->left;
} else if (v > 0) {
prev = &cur->right;
cur = cur->right;
} else {
prev = &cur->same;
new->same = cur->same;
if (cur->same != NULL)
cur->same->parentp = &new->same;
break;
}
}
*prev = new;
new->parentp = prev;
return 0;
}
static HashElement *find(HashElement *pos, void *elem)
{
HashElement *v;
if (pos == NULL)
return NULL;
if (pos->val == elem)
return pos;
if (pos->left != NULL && (v = find(pos->left, elem)) != NULL)
return v;
if (pos->right != NULL && (v = find(pos->right, elem)) != NULL)
return v;
if (pos->same != NULL && (v = find(pos->same, elem)) != NULL)
return v;
return NULL;
}
/*
** Remove a particular element from the hash table, done using pointer compares
*/
int HashRemove(HashTable *tbl, int value, void *elem)
{
HashElement *v;
if (elem == NULL || tbl == NULL)
return 1;
if ((v = find(tbl->table[value], elem)) == NULL)
return 0;
if (v->same != NULL) {
/*
** Same links are not allowed to have left & right children
** so just inherit the parent's children.
*/
if (v->left != NULL)
v->left->parentp = &v->same->left;
if (v->right != NULL)
v->right->parentp = &v->same->right;
v->same->left = v->left;
v->same->right = v->right;
*v->parentp = v->same;
v->same->parentp = v->parentp;
} else if (v->left != NULL) {
*v->parentp = v->left;
v->left->parentp = v->parentp;
if (v->right != NULL) {
HashElement *cur = v->left, **prev = &v->left;
while (cur != NULL) {
if (tbl->cmp(cur->val, v->right->val) < 0) {
prev = &cur->left;
cur = cur->left;
} else {
prev = &cur->right;
cur = cur->right;
}
}
*prev = v->right;
v->right->parentp = prev;
}
} else {
/* no left side, just attach the right */
*v->parentp = v->right;
if (v->right != NULL)
v->right->parentp = v->parentp;
}
free(v);
return 1;
}
static int overAll(HashElement *elem, int (*func)(void *))
{
if (elem == NULL)
return 0;
if (elem->val != NULL)
func(elem->val);
return overAll(elem->left, func) ||
overAll(elem->right, func) ||
overAll(elem->same, func);
}
int HashAll(HashTable *tbl, int (*func)(void *))
{
int i;
if (tbl == NULL)
return 0;
for (i = 0; i < tbl->nelem; i++)
if (overAll(tbl->table[i], func))
return 1;
return 0;
}